package com.haiyi.activiti.engine.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.ParameterizedType;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author yujiakui
 * @version 1.0
 * Email: jkyu@haoyi-info.com
 * date: 2018/6/28 17:13
 * description：通用服务器工厂
 **/
public abstract class CommonServiceFactory<KeyType, ServiceType extends TypeRegistService> implements ApplicationContextAware, InitializingBean {

    /**
     * spring 上下文
     */
    private ApplicationContext applicationContext;

    /**
     * 请求处理和对应的string映射关系
     */
    protected Map<KeyType, ServiceType> requestHandleServiceMap = new ConcurrentHashMap<>();

    /**
     * 根据类型获取对应的服务类
     *
     * @param type
     * @return
     */
    public ServiceType getRequestServiceByType(KeyType type) {
        ServiceType requestHandleService = requestHandleServiceMap.get(type);
        if (null == requestHandleService) {
            throw new RuntimeException(MessageFormat.format("类型type={0}对应的校验器不存在", type));
        }
        return requestHandleService;
    }

    /*
     *
     * @see
     * org.springframework.context.ApplicationContextAware#setApplicationContext
     * (org.springframework.context.ApplicationContext)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;

    }

    /*
     *
     * @see
     * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() throws Exception {

        Class<ServiceType> serviceTypeClass = getServiceInterfaceType();
        // 获取实现validator接口的bean，然后将这种bean注入到工厂的map中
        Map<String, ServiceType> serviceBeanMap = applicationContext
                .getBeansOfType(serviceTypeClass);
        // 防止并发情况注入
        Map<KeyType, ServiceType> tempServiceMap = new HashMap<>(this.requestHandleServiceMap);
        for (Map.Entry<String, ServiceType> entryEle : serviceBeanMap.entrySet()) {
            ServiceType requestHandleService = entryEle.getValue();
            List<KeyType> serviceTypes = requestHandleService.getServiceTypes();
            for (KeyType serviceType : serviceTypes) {
                ServiceType tempRequestHandleService = tempServiceMap.get(serviceType);
                if (null != tempRequestHandleService) {
                    if (!tempRequestHandleService.equals(requestHandleService)) {
                        throw new RuntimeException(
                                MessageFormat.format("在校验器工厂中进行注入得到同一个type={0}对应多个校验器对象={1},{2}",
                                serviceType, requestHandleService, tempRequestHandleService));
                    }
                } else {
                    tempServiceMap.put(serviceType, requestHandleService);
                }
            }

        }

        this.requestHandleServiceMap = tempServiceMap;
    }

    /**
     * 获取对应的服务接口类型
     *
     * @return
     */
    private Class<ServiceType> getServiceInterfaceType() {
        return (Class<ServiceType>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
    }

}